package api

import (
	"github.com/gin-gonic/gin"
	"hub.hddznet.com/app/framework/tools"
	"hub.hddznet.com/app/framework/service/mgo"
	"github.com/dgrijalva/jwt-go"
	"hub.hddznet.com/app/framework/app"
	"encoding/json"
	"strings"
	"strconv"
	"time"
	"hub.hddznet.com/app/framework/action"
	"hub.hddznet.com/uniplatform/framework/logging"
	"gopkg.in/mgo.v2/bson"
	"fmt"
	"hub.hddznet.com/app/framework/app/engines"
)

// 目前值记录json请求和form表单请求的数据，也就是application/json或者multipart/form-data
func (this *mgo_log) LogIn() func(c *gin.Context) {
	// 若是配置文件中没有设置需要记录mongo日志，则提供一个空的方法
	if !app.MustBool("logging", "apilog.mgo", false) {
		return func(c *gin.Context) {}
	}

	return func(c *gin.Context) {
		beanApi := new(mgo.BeanApi)
		// 1. 插入header数据
		this.logInHeader(c, beanApi)
		// 2. 插入请求头
		this.logInBody(c, beanApi)
		// 3. 保存userID等用户信息
		this.logInUserId(c, beanApi)
		// 4. 保存path请求路径
		this.logInPath(c, beanApi)
		// 5. 保存请求IP地址
		beanApi.Ip = c.ClientIP()

		db.AppLog.API.HDInsert(beanApi)
		c.Set("logid", *beanApi.ID)
		c.Set("logtimestart", time.Now().UnixNano())
	}
}
func (this *mgo_log) logInHeader(c *gin.Context, beanApi *mgo.BeanApi) {
	header := map[string]interface{}{}
	for k, v := range c.Request.Header {
		if len(v) == 1 {
			header[k] = v[0]
		} else if len(v) > 1 {
			header[k] = v
		}
	}
	beanApi.Header = header
}

func (this *mgo_log) logInUserId(c *gin.Context, beanApi *mgo.BeanApi) {
	token := c.GetHeader("Authorization")
	if token != "" {
		tk, _ := jwt.Parse(token, nil)
		tmap := tools.MapByInterface(tk.Claims)
		uid, ok := tmap["uid"]
		if ok {
			beanApi.User = uid
		}
	}
}

func (this *mgo_log) logInPath(c *gin.Context, beanApi *mgo.BeanApi) {
	url := c.Request.URL.String()
	if c.Request.URL.RawQuery == "" {
		beanApi.Path = url
	} else {
		beanApi.Path = url + "?" + c.Request.URL.RawQuery
	}
}

func (this *mgo_log) logInBody(c *gin.Context, beanApi *mgo.BeanApi) {
	data := app.GinBodyData(c)
	if strings.Contains(c.GetHeader("Content-Type"), "form-data") {
		c.Request.ParseForm()
		lendata := len(data)
		strdata := strconv.Itoa(lendata)
		len64data, _ := strconv.ParseInt(strdata, 10, 64)
		c.Request.ParseMultipartForm(len64data)
		beanApi.Body = c.Request.PostForm
	} else {
		mapdata := map[string]interface{}{}
		err := json.Unmarshal(data, &mapdata)
		if err == nil {
			beanApi.Body = mapdata
		}
	}

}

func (this *mgo_log) LogOut(c *gin.Context, code int, result interface{}) {
	if !app.MustBool("logging", "apilog.mgo", false) {
		return
	}
	logstart, ok := c.Get("logtimestart")
	t := float64(0)
	if ok {
		t2, ok := logstart.(int64)
		if ok {
			f1, _ := strconv.ParseFloat(strconv.FormatInt(t2, 10), 10)
			f2, _ := strconv.ParseFloat(strconv.FormatInt(time.Now().UnixNano(), 10), 10)
			t = (f2 - f1) / 1e9
		}
	}

	logid, ok := c.Get("logid")
	if !ok {
		logging.Error("logid不存在")
		return
	}
	logidstr, ok := logid.(string)
	if !ok {
		logging.Error("记入日志的时候，强制转换失败")
		return
	}

	beanApi := new(mgo.BeanApi)
	beanApi.ID = &logidstr
	if code != 0 {
		beanApi.Result = result
	}
	beanApi.Used = t
	db.AppLog.API.UpdateId(logid, bson.M{"$set": bson.M{"used": beanApi.Used, "result": beanApi.Result}})
}

type mgo_log struct{}

var Mgolog *mgo_log

func init() {
	Mgolog = new(mgo_log)

	// 判断是否记录API接口调用日志(login )
	action.BeforeRegisterGroups(func() {
		engines.Gin.Use(Mgolog.LogIn())
	})

	action.BeforeReturnData(func(c *gin.Context, res interface{}) {
		r, err := tools.TsnObjToMap(res)
		if err == nil {
			code, ok := r["Code"]
			if ok {
				codeint, err := strconv.Atoi(fmt.Sprintf("%v", code))
				if err == nil {
					Mgolog.LogOut(c, codeint, res)
				}
			}
		}
	})
}
